/************************************************************************
Copyright (c) 2010, 2013, C.R. All rights reserved. 

E-mail: crtoyou@gmail.com; crtoyou@163.com

You can redistribute it and/or modify it under the terms of the
GNU Lesser General Public License as published by the
Free Software Foundation version 3 of the License.

This source code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. if not, write to the Free Software Foundation, Inc., 
51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
************************************************************************/

//#pragma once
//#include <winhttp.h>
//#pragma comment(lib, "winhttp")
//
//enum http_status
//{
//	HTTP_ERROR,
//	HTTP_ERROR_CODE,
//	HTTP_DOWNLOADING,
//	HTTP_FINISH
//};
//
//typedef BOOL (CALLBACK * DownloadCallback)(void*, http_status, int, int);
//
//class HttpAgent
//{
//public:
//	HttpAgent(LPCWSTR szAgent = L"Mozilla/5.0")
//		: m_dwRequestFlags(0)
//	{
//		m_hSession = ::WinHttpOpen(szAgent, 
//			WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, 
//			WINHTTP_NO_PROXY_NAME, 
//			WINHTTP_NO_PROXY_BYPASS, 0);
//		m_hConnect = NULL;
//		if (!m_hSession)
//			throw exception<HttpAgent>(0);
//		OnOpenSession(m_hSession);
//		// retrieve IE proxy settings
//		WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxy_config;
//		if (::WinHttpGetIEProxyConfigForCurrentUser(&proxy_config))
//		{
//			if (proxy_config.lpszAutoConfigUrl)
//				m_strAutoConfigUrl = proxy_config.lpszAutoConfigUrl;
//			if (proxy_config.lpszProxy)
//				SetProxyInfo(proxy_config.lpszProxy, proxy_config.lpszProxyBypass);
//		}
//		if (proxy_config.lpszAutoConfigUrl)
//			::GlobalFree(proxy_config.lpszAutoConfigUrl);
//		if (proxy_config.lpszProxy)
//			::GlobalFree(proxy_config.lpszProxy);
//		if (proxy_config.lpszProxyBypass)
//			::GlobalFree(proxy_config.lpszProxyBypass);
//	}
//
//	virtual ~HttpAgent()
//	{
//		if (m_hConnect)
//			::WinHttpCloseHandle(m_hConnect);
//		m_hConnect = NULL;
//		if (m_hSession)
//			::WinHttpCloseHandle(m_hSession);
//		m_hSession = NULL;
//	}
//
//	HRESULT SetTimeouts(
//		int nResolveTimeout, 
//		int nConnectTimeout, 
//		int nSendTimeout, 
//		int nReceiveTimeout)
//	{
//		if (!m_hSession)
//			return E_FAIL;
//		if (!::WinHttpSetTimeouts(
//			m_hSession,
//			nResolveTimeout,
//			nConnectTimeout,
//			nSendTimeout,
//			nReceiveTimeout))
//			return AtlHresultFromLastError();
//		return S_OK;
//	}
//
//	void setHostBase(LPCWSTR pszHost)
//	{
//		AnalyzeUrl(pszHost);
//	}
//
//	HRESULT httpGet(LPCWSTR pszUrl, const string& sGetData, string& strResponse)
//	{
//		HRESULT hr = E_FAIL;
//		LPCWSTR pwszAcceptTypes = WINHTTP_DEFAULT_ACCEPT_TYPES;
//		wstring url_path = AnalyzeUrl(pszUrl);
//		if (sGetData.size())
//		{
//			wstring wsGetData;
//			int nLen = ::MultiByteToWideChar(CP_ACP, 0, sGetData.data(), sGetData.size(), NULL, 0);
//			if (nLen)
//			{
//				wsGetData.resize(nLen);
//				::MultiByteToWideChar(CP_ACP, 0, sGetData.data(), sGetData.size(), const_cast<wchar_t*>(wsGetData.data()), nLen);
//				url_path.append(L"?");
//				url_path.append(wsGetData);
//			}
//		}
//		HINTERNET hRequest = ::WinHttpOpenRequest(m_hConnect, NULL, url_path.c_str(), NULL, WINHTTP_NO_REFERER, &pwszAcceptTypes, m_dwRequestFlags);
//		OnOpenRequest(hRequest);
//		if (::WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0))
//		{
//			if (::WinHttpReceiveResponse(hRequest, NULL))
//			{
//				DWORD dwStatus = GetDwordResponse(hRequest, WINHTTP_QUERY_STATUS_CODE);
//				if (OnReceiveResponse(hRequest, dwStatus) && (dwStatus < 400))
//				{
//					if (dwStatus != HTTP_STATUS_OK)
//					{
//						ATLTRACE2("Response Code %d", dwStatus);
//					}
//					strResponse = GetResponseContent(hRequest);
//					hr = S_OK;
//				}
//			}
//			else
//			{
//				hr = AtlHresultFromLastError();
//			}
//		}
//		else
//		{
//			hr = AtlHresultFromLastError();
//		}
//		::WinHttpCloseHandle(hRequest);
//
//		return hr;
//	}
//
//	HRESULT httpPost(LPCWSTR pszUrl, const string & sPostData, string & strResponse)
//	{
//		HRESULT hr = E_FAIL;
//		LPCWSTR pwszAcceptTypes = WINHTTP_DEFAULT_ACCEPT_TYPES;
//		wstring url_path = AnalyzeUrl(pszUrl);
//		HINTERNET hRequest = ::WinHttpOpenRequest(m_hConnect, L"POST", url_path.c_str(), NULL, WINHTTP_NO_REFERER, &pwszAcceptTypes, m_dwRequestFlags);
//		OnOpenRequest(hRequest);
//		::WinHttpAddRequestHeaders(hRequest, L"Content-Type: application/x-www-form-urlencoded", ~0, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE);
//		if (::WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, const_cast<char*>(sPostData.c_str()), sPostData.size(), sPostData.size(), 0))
//		{
//			if (::WinHttpReceiveResponse(hRequest, NULL))
//			{
//				DWORD dwStatus = GetDwordResponse(hRequest, WINHTTP_QUERY_STATUS_CODE);
//				if (OnReceiveResponse(hRequest, dwStatus) && (dwStatus < 400))
//				{
//					if (dwStatus != HTTP_STATUS_OK)
//					{
//						ATLTRACE2("Response Code %d", dwStatus);
//					}
//					strResponse = GetResponseContent(hRequest);
//					hr = S_OK;
//				}
//			}
//			else
//			{
//				hr = AtlHresultFromLastError();
//			}
//		}
//		else
//		{
//			hr = AtlHresultFromLastError();
//		}
//		::WinHttpCloseHandle(hRequest);
//
//		return hr;
//	}
//
//	HRESULT httpPut(LPCWSTR pszUrl, const string & sPutData, string & strResponse)
//	{
//		HRESULT hr = E_FAIL;
//		LPCWSTR pwszAcceptTypes = WINHTTP_DEFAULT_ACCEPT_TYPES;
//		wstring url_path = AnalyzeUrl(pszUrl);
//		HINTERNET hRequest = ::WinHttpOpenRequest(m_hConnect, L"PUT", url_path.c_str(), NULL, WINHTTP_NO_REFERER, &pwszAcceptTypes, m_dwRequestFlags);
//		OnOpenRequest(hRequest);
//		if (::WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0))
//		{
//			DWORD dwDummy;
//			::WinHttpWriteData(hRequest, sPutData.c_str(), sPutData.size(), &dwDummy);
//			if (::WinHttpReceiveResponse(hRequest, NULL))
//			{
//				DWORD dwStatus = GetDwordResponse(hRequest, WINHTTP_QUERY_STATUS_CODE);
//				if (OnReceiveResponse(hRequest, dwStatus) && (dwStatus < 400))
//				{
//					if (dwStatus != HTTP_STATUS_OK)
//					{
//						ATLTRACE2("Response Code %d", dwStatus);
//					}
//					strResponse = GetResponseContent(hRequest);
//					hr = S_OK;
//				}
//			}
//			else
//			{
//				hr = AtlHresultFromLastError();
//			}
//		}
//		::WinHttpCloseHandle(hRequest);
//		return hr;
//	}
//
//	HRESULT httpGetFile(LPCWSTR pszUrl, LPCTSTR szFile, FileDownloadCallback cb = NULL, void * para = NULL)
//	{
//		HRESULT hr = E_FAIL;
//		LPCWSTR pwszAcceptTypes = WINHTTP_DEFAULT_ACCEPT_TYPES;
//		wstring url_path = AnalyzeUrl(pszUrl);
//		HINTERNET hRequest = ::WinHttpOpenRequest(m_hConnect, NULL, url_path.c_str(), NULL, WINHTTP_NO_REFERER, &pwszAcceptTypes, m_dwRequestFlags);
//		OnOpenRequest(hRequest);
//		if (::WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0))
//		{
//			if (::WinHttpReceiveResponse(hRequest, NULL))
//			{
//				DWORD dwStatus = GetDwordResponse(hRequest, WINHTTP_QUERY_STATUS_CODE);
//				if (OnReceiveResponse(hRequest, dwStatus))
//				{
//					if (dwStatus < 400)
//					{
//						if (dwStatus != HTTP_STATUS_OK)
//						{
//							ATLTRACE2("Response Code %d", dwStatus);
//						}
//						hr = GetContentToFile(hRequest, szFile, cb, para);
//					}
//					else if (cb)
//					{
//						cb(para, HTTP_ERROR_CODE, dwStatus, 0);
//					}
//				}
//			}
//			else
//			{
//				hr = AtlHresultFromLastError();
//			}
//		}
//		else
//		{
//			hr = AtlHresultFromLastError();
//		}
//		::WinHttpCloseHandle(hRequest);
//
//		return hr;
//	}
//
//	// interface
//	virtual void OnOpenSession(HINTERNET hSession) {};
//	virtual void OnOpenConnect(HINTERNET hConnect) {};
//	virtual void OnOpenRequest(HINTERNET hRequest) {};
//
//	virtual BOOL OnReceiveResponse(HINTERNET hRequest, DWORD dwHttpStatus)
//	{
//		// return FALSE if you want to process data yourself.
//		return TRUE;
//	}
//
//private:
//	bool Connect(LPCWSTR szHost, INTERNET_PORT nPort)
//	{
//		if (m_hConnect)
//		{
//			if ((m_CurrentHost == szHost) && (m_CurrentPort == nPort))
//				return true;
//			::WinHttpCloseHandle(m_hConnect);
//		}
//		m_CurrentPrefix.clear();
//		m_hConnect = ::WinHttpConnect(m_hSession, szHost, nPort, 0);
//		if (m_hConnect)
//		{
//			OnOpenConnect(m_hConnect);
//			m_CurrentHost = szHost;
//			m_CurrentPort = nPort;
//			return true;
//		}
//		m_CurrentHost.clear();
//		m_CurrentPort = 0;
//		return false;
//	}
//
//	wstring AnalyzeUrl(LPCWSTR szUrl)
//	{
//		if ((_wcsnicmp(szUrl, L"http://", 7) == 0) || (_wcsnicmp(szUrl, L"https://", 8) == 0))
//		{
//			URL_COMPONENTS url_component = {0};
//			WCHAR szScheme[10], szHost[100], szUrlPath[512], szExtra[512];
//			url_component.dwStructSize = sizeof(url_component);
//			url_component.lpszScheme = szScheme;
//			url_component.dwSchemeLength = _countof(szScheme);
//			url_component.lpszHostName = szHost;
//			url_component.dwHostNameLength = _countof(szHost);
//			url_component.lpszUrlPath = szUrlPath;
//			url_component.dwUrlPathLength = _countof(szUrlPath);
//			url_component.lpszExtraInfo = szExtra;
//			url_component.dwExtraInfoLength = _countof(szExtra);
//			::WinHttpCrackUrl(szUrl, wcslen(szUrl), 0, &url_component);
//			if (Connect(szHost, url_component.nPort))
//			{
//				m_CurrentPrefix = szUrlPath;
//				if (url_component.nScheme == INTERNET_SCHEME_HTTPS)
//					m_dwRequestFlags = WINHTTP_FLAG_SECURE;
//				else
//					m_dwRequestFlags = 0;
//			}
//			return szUrlPath;
//		}
//		else
//		{
//			return m_CurrentPrefix + szUrl;
//		}
//	}
//
//	DWORD GetDwordResponse(HINTERNET hRequest, DWORD dwInfoLevel)
//	{
//		DWORD dwStatus = 0, dwBufferLength = sizeof(dwStatus);
//		::WinHttpQueryHeaders(hRequest, dwInfoLevel | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &dwStatus, &dwBufferLength, WINHTTP_NO_HEADER_INDEX);
//		return dwStatus;
//	}
//
//	string GetResponseContent(HINTERNET hRequest)
//	{
//		string strResponse;
//		DWORD dwTotalByte = GetDwordResponse(hRequest, WINHTTP_QUERY_CONTENT_LENGTH);
//
//		DWORD dwRead = 0;
//		string strTmp;
//		do
//		{
//			dwRead = 0;
//			DWORD dwDummy = 0;
//			::WinHttpQueryDataAvailable(hRequest, &dwRead);
//			if (dwRead)
//			{
//				strTmp.resize(dwRead);
//				::WinHttpReadData(hRequest, const_cast<char*>(strTmp.c_str()), dwRead, &dwDummy);
//				strResponse.append(strTmp, 0, dwDummy);
//			}
//		} while (dwRead > 0);
//		if (dwTotalByte)
//		{
//			ATLASSERT(dwTotalByte == strResponse.size());
//		}
//		return strResponse;
//	}
//
//	HRESULT GetContentToFile( HINTERNET hRequest, LPCTSTR szFile, FileDownloadCallback cb, void * para )
//	{
//		DWORD dwTotalByte = GetDwordResponse(hRequest, WINHTTP_QUERY_CONTENT_LENGTH);
//		HRESULT hr = E_FAIL;
//		DWORD dwRead = 0;
//		string strTmp;
//		int nCurrent = 0;
//		int nTotal = dwTotalByte;
//		HANDLE hFile = ::CreateFile(szFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
//		if (hFile != INVALID_HANDLE_VALUE)
//		{
//			int nGet = 0;
//			do
//			{
//				dwRead = 0;
//				DWORD dwDummy = 0;
//				::WinHttpQueryDataAvailable(hRequest, &dwRead);
//				if (dwRead)
//				{
//					strTmp.resize(dwRead);
//					::WinHttpReadData(hRequest, const_cast<char*>(strTmp.c_str()), dwRead, &dwDummy);
//					nCurrent += dwDummy;
//					::WriteFile(hFile, strTmp.c_str(), strTmp.size(), &dwDummy, NULL);
//					if (cb)
//						if (!cb(para, HTTP_DOWNLOADING, nCurrent, nTotal))
//							break;
//				}
//			} while (dwRead > 0);
//			::CloseHandle(hFile);
//			if (dwTotalByte)
//			{
//				if (nCurrent == dwTotalByte)
//				{
//					hr = S_OK;
//				}
//				else
//				{
//					hr = E_FAIL;
//				}
//			}
//			else
//			{
//				hr = S_OK;
//			}
//		}
//		else
//			hr = AtlHresultFromLastError();
//		if (cb)
//		{
//			if (SUCCEEDED(hr))
//				cb(para, HTTP_FINISH, nCurrent, nTotal);
//			else
//				cb(para, HTTP_ERROR, (int)(hr), nTotal);
//		}
//		return hr;
//	}
//
//	void SetProxyInfo(LPWSTR szProxy, LPWSTR szProxyBypass, LPWSTR szProxyUserName = NULL, LPWSTR szProxyPassword = NULL)
//	{
//		WINHTTP_PROXY_INFO proxy_info;
//		proxy_info.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
//		proxy_info.lpszProxy = szProxy;
//		proxy_info.lpszProxyBypass = szProxyBypass;
//		::WinHttpSetOption(m_hSession, WINHTTP_OPTION_PROXY, &proxy_info, sizeof(proxy_info));
//		if (szProxyUserName)
//		{
//			::WinHttpSetOption(m_hSession, WINHTTP_OPTION_PROXY_USERNAME, szProxyUserName, wcslen(szProxyUserName));
//		}
//		if (szProxyPassword)
//		{
//			::WinHttpSetOption(m_hSession, WINHTTP_OPTION_PROXY_PASSWORD, szProxyPassword, wcslen(szProxyPassword));
//		}
//	}
//
//private:
//	DWORD m_dwRequestFlags;
//	wstring m_strAutoConfigUrl;
//	HINTERNET m_hSession;
//	HINTERNET m_hConnect;
//	wstring m_CurrentHost, m_CurrentPrefix;
//	INTERNET_PORT m_CurrentPort;
//
//};
//
////////////////////////////////////////////////////////////////////////////
////WinHttpCheckPlatform
////WinHttpCreateProxyResolver
////WinHttpCreateUrl
////WinHttpDetectAutoProxyConfigUrl
////WinHttpGetDefaultProxyConfiguration
////WinHttpGetProxyForUrl
////WinHttpGetProxyForUrlEx
////WinHttpQueryAuthSchemes
////	WinHttpQueryOption
////WinHttpResetAutoProxy
////WinHttpSetCredentials
////WinHttpSetDefaultProxyConfiguration
////	WinHttpSetOption
////WinHttpSetStatusCallback
////	WinHttpSetTimeouts
////WinHttpTimeFromSystemTime
////WinHttpTimeToSystemTime
////////////////////////////////////////////////////////////////////////////
